package net.dfx.iot_download_tool.impl;

import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLContext;

import org.apache.commons.lang3.StringUtils;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.config.ConnectionConfig;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.io.HttpClientResponseHandler;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;

import net.dfx.iot_download_tool.enu.LocalZoneEnum;
import net.dfx.iot_download_tool.enu.ReqUrlEnum;
import net.dfx.iot_download_tool.itf.IMutiExec;
import net.dfx.iot_download_tool.utils.SSLUtil;
import net.dfx.iot_download_tool.vo.ApikeyVO;
import net.dfx.iot_download_tool.vo.ConfVO;
import net.dfx.iot_download_tool.vo.LocalSETimeVO;
import net.dfx.iot_download_tool.vo.MutileDataVO;
import net.dfx.iot_download_tool.vo.UserEnterVO;

public class MutiExecImpl implements IMutiExec {
	
	private ApikeyVO apiKey;
	private UserEnterVO userEnter;
	private ConfVO confVO;
	static Logger logger = LogManager.getLogger(MutiExecImpl.class);
	private CloseableHttpClient httpClient;
	
	/**
	 * 无参构造函数
	 */
	public MutiExecImpl() {
		super();
		this.httpClient = createUnsafeHttpClient();
	}

	/**
	 * 有参构造函数
	 * @param apiKey {@link ApikeyVO} Apikey配置类
	 * @param userEnter {@link UserEnterVO} 用户输入参数配置类
	 * @param confVO {@link ConfVO} 线程池及线连池、数据库连接池配置类
	 */
	public MutiExecImpl(ApikeyVO apiKey, UserEnterVO userEnter, ConfVO confVO) {
		super();
		this.apiKey = apiKey;
		this.userEnter = userEnter;
		this.confVO = confVO;
		this.httpClient = createUnsafeHttpClient();
	}

	@Override
	public void execMoreThread() {
		logger.info("启动线程处理参数请求");
		// 1.主要子线程开启处理，划分处理任务
		DateTimeFormatter fm = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
		
		ExecutorService executor = Executors.newFixedThreadPool(confVO.getThreadConf().getMainNum().getNum());
		Future<List<MutileDataVO>>[] futures = new Future[confVO.getThreadConf().getMainNum().getNum()];
		// 提交 HTTPS 请求任务到线程池
		int equipNNum = userEnter.getEquipNNum();
		int paramNNum = userEnter.getParamNNum();
		int dtRangNum = userEnter.getDTRangNum();
		if (equipNNum>0 && paramNNum>0 && dtRangNum>0) {
			// 2.分子线程开始请求，每个参数构建一个数据库表，用索引表记录设备、参数用来索引，参数表中除了时间和数值还要加上一个索引数字
			List<String> equipNames = userEnter.getEquipName();
			List<String> paramNames = userEnter.getParamName();
			List<LocalSETimeVO> datetimeRangs = userEnter.getDatetimeRang();
			
			switch (equipNNum) {
			case 1:
				// 只有一个设备名称的情况下
				String equip_1 = equipNames.get(0);
				switch (paramNNum) {
				case 1:
					// 只有一个参数的情况下
					String param_1 = paramNames.get(0);
					switch (dtRangNum) {
					case 1:
						// 只有一个时间范围情况下
						LocalSETimeVO dtr_1 = datetimeRangs.get(0);
						// 创建响应处理器（定义如何处理服务器响应）
						HttpClientResponseHandler<String> resHandler_1 = response -> {
							int statusCode = response.getCode();
							if (statusCode >= 200 && statusCode < 300) {
								HttpEntity entity = response.getEntity();
								try {
									String resJson = EntityUtils.toString(entity);
									EntityUtils.consume(entity); // &#9989; 显式消费实体
									return resJson;
								} catch (IOException e) {
									throw new RuntimeException("Failed to read response", e);
								}
							} else {
								return "";
							}
						};
						// 如果不超过4天，则不需要开启线程
						// 开始时间终止时间对象
						String inS_1 = equip_1 + "@" + param_1;
						String tags = URLEncoder.encode(inS_1, StandardCharsets.UTF_8);
						String reqUrl = ReqUrlEnum.REQURL.getUrlStr();
						
						long dateNum_1 = dtr_1.getDateNum();
						if (dateNum_1>4L) {
							// 开启多线程处理并回收结果到主线程
							
						} else {
							// 直接循环处理
							logger.info("开始发起请求-A_1");
							long startSec_1 = dtr_1.getStartSec();
							long endSec_1 = dtr_1.getEndSec();
							if (dateNum_1>1L) {
								long dateNumSub_1 = dateNum_1 - 1L;
								for (long i = 0; i < dateNumSub_1; i++) {
									long middleSec_1 = startSec_1 + 24L * 60L * 60L;
									String reqUri_11 = reqUrl + "?tags=" + tags + "&startTime=" + startSec_1 + "&endTime=" + middleSec_1 + "&interval=&limit=" + 1000000L;
									HttpGet hg = new HttpGet(reqUri_11);
									hg.setHeader("Authorization", apiKey.getApikey());
									hg.setHeader("Content-Type", "application/json;charset=UTF-8");
									hg.setConfig(
											RequestConfig
											.custom()
											.setConnectionRequestTimeout(confVO.getConnectConf().getConnectTimeOut().getNum(), TimeUnit.MILLISECONDS)
											.setResponseTimeout(confVO.getConnectConf().getResponseTimeOut().getNum(), TimeUnit.MILLISECONDS)
											.build()
											);
									String resp_11 = "";
									try {
										resp_11 = httpClient.execute(hg, resHandler_1);
									} catch (IOException e) {
										logger.error("请求获取设备-"+equip_1+"参数-"+param_1+"数据失败", e);
										continue;
									}
									if (StringUtils.isNotBlank(resp_11)) {
										JSONObject rootObj_11 = JSONObject.parseObject(resp_11);
										if (rootObj_11 != null) {
											JSONObject dataObj_11 = rootObj_11.getJSONObject("data");
											if (dataObj_11 != null) {
												JSONObject itemsObj_11 = dataObj_11.getJSONObject("items");
												if (itemsObj_11 != null && !itemsObj_11.isEmpty()) {
													JSONArray dataArr_11 = itemsObj_11.getJSONArray(inS_1);
													if (dataArr_11 != null && !dataArr_11.isEmpty()) {
														StringBuilder sb_11 = new StringBuilder();
														sb_11.append("INSERT INTO ");
														// TODO-添加表名
														sb_11.append("(id, ts, vl, no) VALUES ");
														for (Object object_11 : dataArr_11) {
															JSONObject objs = (JSONObject) object_11;
															long tiLon = objs.getLong("timestamp");
															Instant tiIn = Instant.ofEpochMilli(tiLon);
															LocalDateTime ltime = LocalDateTime.ofInstant(tiIn, LocalZoneEnum.CHINAZONE.getZone());
															sb_11.append("(").append(ltime.format(fm)).append(", ");
															BigDecimal dc = objs.getBigDecimal("value");
															sb_11.append(dc.toPlainString()).append("),");
														}
														// 清除末尾的,字符然后插入;
														sb_11.delete(sb_11.length()-1, sb_11.length()).append(";");
													}
												}
											}
										}
									}
									
									startSec_1 = middleSec_1 + 1L;
								}
								String reqUri_12 = reqUrl + "?tags=" + inS_1 + "&startTime=" + startSec_1 + "&endTime=" + endSec_1 + "&interval=&limit=" + 1000000L;
							} else {
								//
							}
						}
						break;
					default:
						// 多个时间范围情况下
						// 开启线程
						
						// 如果不超过4天，则不需要开启线程
						break;
					}
					break;
				default:
					// 多个参数的情况下
					break;
				}
				break;
			default:
				// 多个设备名称的情况下
				switch (paramNNum) {
				case 1:
					// 只有一个参数的情况下
					switch (dtRangNum) {
					case 1:
						// 只有一个时间范围情况下
						// 如果不超过4天，则不需要开启线程
						break;
					default:
						// 多个时间范围情况下
						// 如果不超过4天，则不需要开启线程
						break;
					}
					break;
				default:
					// 多个参数的情况下
					break;
				}
				break;
			}
			// 3.遍历一个设备的所有参数表，按照同一的索引汇总到一个表中
		}
	}
	
	/**
	 * 初始化连接池
	 * 
	 * @return CloseableHttpClient
	 */
	private CloseableHttpClient createUnsafeHttpClient() {
		try {
			// 创建无条件信任的SSL上下文
			SSLContext sc = SSLUtil.createAll();
			// 配置连接池管理器
			return HttpClients.custom()
					.setConnectionManager(PoolingHttpClientConnectionManagerBuilder.create()
							.setTlsSocketStrategy(new DefaultClientTlsStrategy(sc, NoopHostnameVerifier.INSTANCE))
							.setMaxConnTotal(confVO.getConnectConf().getPoolSize().getNum())
							// 设置每主机最大连接数
							.setMaxConnPerRoute(confVO.getConnectConf().getPerHost().getNum())
							.setDefaultConnectionConfig(
									ConnectionConfig.custom().setConnectTimeout(confVO.getConnectConf().getConnectTimeOut().getNum(), TimeUnit.MILLISECONDS)
											.setSocketTimeout(confVO.getConnectConf().getResponseTimeOut().getNum(), TimeUnit.MILLISECONDS)
											.setValidateAfterInactivity(5000, TimeUnit.MILLISECONDS).build())
							.build())
					.build();
		} catch (Exception e) {
			throw new RuntimeException("创建HTTP client失败", e);
		}
	}

}
